// 5-1 C++ 接口（抽象类）- 实例
/**
 * 面向对象的编程语言有封装、继承 、抽象、多态等4个主要的特征
 * C++ 接口（抽象类）
 * 接口描述了类的**行为和功能**，而**不需要**完成类的特定实现。
 * 
 * C++ 接口是使用**抽象类**来实现的，抽象类与**数据抽象**互不混淆，数据抽象是一个把实现细节与相关的数据分离开的概念。
 * 
 * 如果类中至少有一个函数被声明为纯虚函数，则这个类就是抽象类。纯虚函数是通过在声明中使用 "= 0" 来指定的，如下所示:
      
      class Box
      {
        public:
            // 纯虚函数
            virtual double getVolume() = 0;
        private:
            double length;      // 长度
            double breadth;     // 宽度
            double height;      // 高度
      };

 * 设计抽象类（通常称为 ABC）的目的，是为了给其他类提供一个可以继承的适当的基类。抽象类不能被用于实例化对象，它只能作为接口使用。如果试图实例化一个抽象类的对象，会导致编译错误。

 * 因此，如果一个 ABC 的子类需要被实例化，则必须实现每个虚函数，这也意味着 C++ 支持使用 ABC 声明接口。如果没有在派生类中重写纯虚函数，就尝试实例化该类的对象，会导致编译错误。

 * 可用于实例化对象的类被称为具体类。

 * -----------start-----------------
 * 抽象类的实例
 * 请看下面的实例，基类 Shape 提供了一个接口 getArea()，在两个派生类 Rectangle 和 Triangle 中分别实现了 getArea()：
 * 
 
      Rectangle class area : 12
      Triangle class area : 10
 * 从上面的实例中，我们可以看到一个抽象类是如何定义一个接口 getArea()，两个派生类是如何通过不同的计算面积的算法来实现这个相同的函数。
 * -----------end--------------------
 * 设计策略
 * 面向对象的系统可能会使用一个抽象基类为所有的外部应用程序提供一个适当的、通用的、标准化的接口。然后，派生类通过继承抽象基类，就把所有类似的操作都继承下来。

 * 外部应用程序提供的功能（即公有函数）在抽象基类中是以纯虚函数的形式存在的。这些纯虚函数在相应的派生类中被实现。

 * 这个架构也使得新的应用程序可以很容易地被添加到系统中，即使是在系统被定义之后依然可以如此。
 
*/
#include <iostream>

class Shape{
  protected:
    int width;
    int height;

  // public:
  private:
    // 访问修饰符不影响虚函数/纯虚函数的重写
    virtual void printArea() = 0;// 提供接口框架的纯虚函数
  public:
    void setWidth(int w){
      width = w;
    }
    void setHeight(int h){
      height = h;
    }

};

class Rectangle : public Shape{
  public:
    void printArea(){
      std::cout << "Rectangle class area : " << (double)(width * height) << std::endl;
    }
};

class Triangle : public Shape{
  public:
    void printArea(){
      std::cout << "Triangle class area : " << (double)(width * height) / 2 << std::endl;
    }
};

int main(void)
{
  Rectangle r1;
  r1.setWidth(3);
  r1.setHeight(4);
  r1.printArea();

  Triangle t1;
  t1.setWidth(4);
  t1.setHeight(5);
  t1.printArea();
  printf("---------------end------------\n");
  return 0;
}